#ifndef NOMINMAX
#define NOMINMAX
#endif

#include "EmailManager.h"
#include "DBlayer.h"
#include "ConfigValues.h"
#include "Defines.h"
#include "LogManager.h"

#include <iostream>   
#include <curl/curl.h>   

#include <vmime/vmime.hpp>
#include <vmime/net/serviceInfos.hpp>
#include <vmime/net/smtp/SMTPTransport.hpp>
#include <vmime/platforms/windows/windowsHandler.hpp>

EmailManager::EmailManager(void)
{
    vmime::platformDependant::setHandler<vmime::platforms::windows::windowsHandler>();
}

EmailManager::~EmailManager(void)
{
}

bool EmailManager::SMSSend(const unsigned int& uiMonitorID)
{
	bool bResult = false;
	//config_email_sms_sender
	char errorBuffer[CURL_ERROR_SIZE];
	CURL *curl;   
    CURLcode result;   
    // Create our curl handle   
    curl = curl_easy_init();   
  
    if (curl)   
    {   
      // Now set up all of the curl options   
	  string url ( config_email_sms_sender );
	  url.append(string("mid="));
	  
	  std:stringstream ss;
	  ss << uiMonitorID; 
	  string strHexPacket(ss.str());
	  url.append(ss.str());	

      curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);   
      curl_easy_setopt(curl, CURLOPT_URL, url);   
      curl_easy_setopt(curl, CURLOPT_HEADER, 0);   
      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);   
      //curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writer);   
      //curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);   
  
      // Attempt to retrieve the remote page   
      result = curl_easy_perform(curl);   
  
      // Always cleanup   
      curl_easy_cleanup(curl);   
  
      // Did we succeed?   
      if (result == CURLE_OK)   
      {   
         LOGT(("EmailManager::SMSSend. OK: \n"));
		 bResult = true; 
      }   
      else  
      {   
        LOGT(("EmailManager::SMSSend. Error: %s\n", errorBuffer));
		bResult = false; 
      }   
	}
	return bResult; 
}

bool EmailManager::SendEmail(   const string& szEmailBody,
                                const string& szEmailFrom,
                                const vector<string>& recipients)
{
    bool bResult = false;
    try
    {
        vmime::ref <vmime::net::session> sess = vmime::create<vmime::net::session>();
        vmime::ref <vmime::net::transport> tr = sess->getTransport("smtp");
        tr->setProperty("server.address", config_emailsender_host);
        tr->setProperty("server.port", config_emailsender_port);
        tr->setProperty("options.need-authentication", config_emailsender_auth);
        tr->setProperty("auth.username", config_emailsender_username);
        tr->setProperty("auth.password", config_emailsender_password);
        vmime::ref <vmime::net::socketFactory> socketFactory = tr->getSocketFactory();
        vmime::mailboxList listTo;
        vector<string>::const_iterator iter;
        for (iter = recipients.begin(); iter != recipients.end(); iter++)
        {
            listTo.appendMailbox(vmime::create<vmime::mailbox>(*iter));
        }
        vmime::utility::inputStreamStringAdapter isAdapter(szEmailBody);
        vmime::mailbox mailBoxFrom;
        mailBoxFrom.parse(szEmailFrom, 0, szEmailFrom.size(), NULL);
        tr->connect();
        tr->send(mailBoxFrom, listTo, isAdapter, szEmailBody.size(), NULL);
        tr->disconnect();
        bResult = true;
    }
    catch (vmime::exception& e)
    {
        LOGT(("EmailManager::SendEmail. VMime exception occurred. Message: %s\n", e.what()));
    }
    catch (std::exception& e)
    {
        LOGT(("EmailManager::SendEmail. Std exception occurred. Message: %s\n", e.what()));
    }
    return bResult;
}

void EmailManager::CreateEmail( const string& szEmailFrom,
                                const string& szEmailTo,
                                const string& szEmailCc,
                                const string& szEmailBcc,
                                const string& szAttachmentFileName,
                                const string& szSubject,
                                const unsigned char& ucEmailContentType,
                                const string& szTemplateText,
                                string& szEmailBody,
                                string& szEmailSender,
                                vector<string>& recipients)
{
    vmime::messageBuilder mb;

    vmime::mailbox mailBoxFrom;
    mailBoxFrom.parse(szEmailFrom, 0, szEmailFrom.size(), NULL);
    vmime::mailbox mailBoxFromUTF8(vmime::text(mailBoxFrom.getName().getWholeBuffer(), W3M_ENCODING), mailBoxFrom.getEmail());
    mb.setExpeditor(mailBoxFromUTF8);
    
    vmime::addressList to;
    vmime::addressList cc;
    char seps[] =";,";
    
    string szEmailToCopy(szEmailTo);
    char *token = strtok((char*)szEmailToCopy.c_str(), seps);
    while(token != NULL)
    {
        vmime::mailbox mailBox;
        mailBox.parse(token, 0, strlen(token), NULL);
        if (find(recipients.begin(), recipients.end(), mailBox.getEmail()) == recipients.end())
        {
            to.appendAddress(vmime::create<vmime::mailbox>(vmime::text(mailBox.getName().getWholeBuffer(), W3M_ENCODING), mailBox.getEmail()));
            recipients.push_back(mailBox.getEmail());
        }        
        token = strtok(NULL, seps);
    }
    mb.setRecipients(to);

    string szEmailCcCopy(szEmailCc);
    token = strtok((char*)szEmailCcCopy.c_str(), seps);
    while(token != NULL)
    {
        vmime::mailbox mailBox;
        mailBox.parse(token, 0, strlen(token), NULL);
        if (find(recipients.begin(), recipients.end(), mailBox.getEmail()) == recipients.end())
        {
            cc.appendAddress(vmime::create<vmime::mailbox>(vmime::text(mailBox.getName().getWholeBuffer(), W3M_ENCODING), mailBox.getEmail()));
            recipients.push_back(mailBox.getEmail());
        }        
        token = strtok(NULL, seps);
    }
    mb.setCopyRecipients(cc);

    string szEmailBccCopy(szEmailBcc);
    token = strtok((char*)szEmailBccCopy.c_str(), seps);
    while(token != NULL)
    {
        vmime::mailbox mailBox;
        mailBox.parse(token, 0, strlen(token), NULL);
        if (find(recipients.begin(), recipients.end(), mailBox.getEmail()) == recipients.end())
        {
            recipients.push_back(mailBox.getEmail());
        }        
        token = strtok(NULL, seps);
    }
    
    mb.setSubject(vmime::text(szSubject, W3M_ENCODING));
    if (ucEmailContentType == CONTENT_TYPE_TEXT_PLAIN)
        mb.constructTextPart(vmime::mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_PLAIN));
    else    
    if (ucEmailContentType == CONTENT_TYPE_TEXT_HTML)
        mb.constructTextPart(vmime::mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_HTML));                
    else
        mb.constructTextPart(vmime::mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_PLAIN));
    mb.getTextPart()->setText(vmime::create<vmime::stringContentHandler>(szTemplateText));
    mb.getTextPart()->setCharset(W3M_ENCODING);
    if (szAttachmentFileName.size())
    {
        vmime::ref <vmime::fileAttachment> att = vmime::create<vmime::fileAttachment>
            (szAttachmentFileName, vmime::mediaType("text/html"),vmime::text("Changes"));
        att->getFileInfo().setFilename("changes.html");
        mb.attach(att);
    }    
    vmime::ref <vmime::message> msg = mb.construct();
    szEmailBody = msg->generate(); 
}

bool EmailManager::CreateEmailOnDemand( const unsigned int& uiMonitorID, 
                                        const unsigned int& uiAccountID, 
                                        const unsigned char& ucEmailContentType,
                                        const string& szEmailFrom,
                                        const string& szEmailTo,
                                        const string& szEmailCc,
                                        const string& szEmailBcc,
                                        const VariablesMap& variables,
                                        const string& szEmailTemplateName,
                                        const string& szEmailSubject,
                                        const string& szEmailTemplateText,
                                        string& szEmailBody,
                                        string& szEmailSender,
                                        vector<string>& recipients)
{
    bool bResult = false;
    try
    {
        string szSubject;
        string szTemplateText;
        string szFrom(szEmailFrom);
        string szTo(szEmailTo);
        string szCc(szEmailCc);
        string szBcc(szEmailBcc);

        string szMonitorEmailTo;
        string szAccountEmailTo;
        string szAccountEmailBcc;
        unsigned char ucContentType;
        
        if (uiMonitorID)
            dbLayer->GetMonitorEmailInfo(uiMonitorID, szMonitorEmailTo, szAccountEmailBcc, ucContentType);
        else
        if (uiAccountID)
            dbLayer->GetAccountEmailInfo(uiAccountID, szAccountEmailTo, szAccountEmailBcc, ucContentType);

        if (!szTo.size())
        {
            if (szMonitorEmailTo.size())
                szTo = szMonitorEmailTo;
            else
            if (szAccountEmailTo.size())
                szTo = szMonitorEmailTo;
        }

        if (szAccountEmailBcc.size())
        {
            if (szBcc.size())
            {
                szBcc += ";";
                szBcc += szAccountEmailBcc;
            }
            else
            {
                szBcc = szAccountEmailBcc;
            }
        }
        
        if (szEmailTemplateName.size())
        {
            string szDefaultEmailFrom;
            string szDefaultEmailTo;
            string szDefaultEmailCc;
            string szDefaultEmailBcc;
            if (!dbLayer->GetEmailTemplate(szEmailTemplateName, szSubject, szTemplateText, szDefaultEmailFrom, szDefaultEmailTo, szDefaultEmailCc, szDefaultEmailBcc))
                return false;
            if (!szFrom.size())
                szFrom = szDefaultEmailFrom;
            if (!szTo.size())
                szTo = szDefaultEmailTo;
            if (!szCc.size())
                szCc = szDefaultEmailCc;
            if (szDefaultEmailBcc.size())
            {
                if (szBcc.size())
                {
                    szBcc += ";";
                    szBcc += szDefaultEmailBcc;
                }
                else
                {
                    szBcc = szDefaultEmailBcc;
                }
            }
        }
        else
        {
            szSubject = szEmailSubject;
            szTemplateText = szEmailTemplateText;
        }
        ReplaceTemplates(szTemplateText);        
        ReplaceVariables(szTemplateText, variables);
        ReplaceTemplates(szSubject);
        ReplaceVariables(szSubject, variables);
        ReplaceVariables(szFrom, variables);
        ReplaceVariables(szTo, variables);
        ReplaceVariables(szCc, variables);
        ReplaceVariables(szBcc, variables);
        if (ucEmailContentType == CONTENT_TYPE_TEXT_PLAIN)
            ConvertTemplateToText(szTemplateText);
        CreateEmail(szFrom, szTo, szCc, szBcc, "", szSubject, ucEmailContentType, szTemplateText, szEmailBody, szEmailSender, recipients);
        szEmailSender = szFrom;
        bResult = true;
    }
    catch (vmime::exception& e)
    {
        LOGT(("EmailManager::CreateEmailOnDemand. VMime exception occurred. Message: %s\n", e.what()));
    }
    catch (std::exception& e)
    {
        LOGT(("EmailManager::CreateEmailOnDemand. Std exception occurred. Message: %s\n", e.what()));
    }
    return bResult;
}

bool EmailManager::CreateEmailWithUrl(  const unsigned int& uiMonitorID, 
                                        const unsigned int& uiAccountID, 
                                        const unsigned int& uiResourceID,
                                        const unsigned char& ucEmailContentType,
                                        const string& szEmailTo,
                                        const string& szEmailBcc,
                                        const string& szMonitorTitle,
                                        const string& szUrl,
                                        const unsigned int& uiQtyTriggers,
                                        const string& szAttachmentFileName,
                                        string& szEmailBody,
                                        string& szEmailSender,
                                        vector<string>& recipients)
{
    bool bResult = false;
    try
    {
        string szSubject;
        string szTemplateText;
        string szDefaultEmailFrom;
        string szDefaultEmailTo;
        string szDefaultEmailCc;
        string szDefaultEmailBcc;
        if (dbLayer->GetEmailTemplate("notify_with_url",  szSubject, szTemplateText, szDefaultEmailFrom, szDefaultEmailTo, szDefaultEmailCc, szDefaultEmailBcc))
        {
            VariablesMap variables;
            stringstream variable;            
            string szDateTime;

            GetGMTDateTime(szDateTime);
            variables.insert(VariablesMapPair("[%current_time%]", szDateTime));
            if (szMonitorTitle.size())
                variables.insert(VariablesMapPair("[%monitor_title%]", szMonitorTitle));
            else
                variables.insert(VariablesMapPair("[%monitor_title%]", szUrl));
            variables.insert(VariablesMapPair("[%monitor_url%]", szUrl));
            variable.str("");
            variable << uiQtyTriggers;
            variables.insert(VariablesMapPair("[%changes_count%]", variable.str()));            
            variable.str("");
            variable << uiAccountID;
            variables.insert(VariablesMapPair("[%account_id%]", variable.str()));
            variable.str("");
            variable << uiMonitorID;
            variables.insert(VariablesMapPair("[%monitor_id%]", variable.str()));
            variable.str("");
            variable << uiResourceID;
            variables.insert(VariablesMapPair("[%resource_id%]", variable.str()));
            ReplaceTemplates(szTemplateText);
            ReplaceVariables(szTemplateText, variables);
            ReplaceTemplates(szSubject);
            ReplaceVariables(szSubject, variables);
            if (ucEmailContentType == CONTENT_TYPE_TEXT_PLAIN)
                ConvertTemplateToText(szTemplateText);
            if (szEmailBcc.size())
            {
                if (szDefaultEmailBcc.size())
                {
                    szDefaultEmailBcc += ";";
                    szDefaultEmailBcc += szEmailBcc;
                }
                else
                {
                    szDefaultEmailBcc = szEmailBcc;
                }
            }
            CreateEmail(szDefaultEmailFrom, szEmailTo, szDefaultEmailCc, szDefaultEmailBcc, szAttachmentFileName, szSubject, ucEmailContentType, szTemplateText, szEmailBody, szEmailSender, recipients);
            szEmailSender = szDefaultEmailFrom;
            bResult = true;
        }
    }
    catch (vmime::exception& e)
    {
        LOGT(("EmailManager::CreateEmailWithUrl. VMime exception occurred. Message: %s\n", e.what()));
    }
    catch (std::exception& e)
    {
        LOGT(("EmailManager::CreateEmailWithUrl. Std exception occurred. Message: %s\n", e.what()));
    }
    return bResult;
}

bool EmailManager::CreateEmailWithChangesSummary(   const unsigned int& uiMonitorID, 
                                                    const unsigned int& uiAccountID,
                                                    const unsigned int& uiResourceID,
                                                    const unsigned char& ucEmailContentType,
                                                    const string& szEmailTo,
                                                    const string& szEmailBcc,
                                                    const string& szMonitorTitle,
                                                    const string& szUrl,
                                                    const unsigned int& uiQtyTriggers,
                                                    const string& szChangesSummary,
                                                    const string& szAttachmentFileName,
                                                    string& szEmailBody,
                                                    string& szEmailSender,
                                                    vector<string>& recipients)
{
    bool bResult = false;
    try
    {
        string szSubject;
        string szTemplateText;
        string szDefaultEmailFrom;
        string szDefaultEmailTo;
        string szDefaultEmailCc;
        string szDefaultEmailBcc;
        if (dbLayer->GetEmailTemplate("notify_with_changes_summary",  szSubject, szTemplateText, szDefaultEmailFrom, szDefaultEmailTo, szDefaultEmailCc, szDefaultEmailBcc))
        {
            VariablesMap variables;
            stringstream variable;            
            string szDateTime;

            GetGMTDateTime(szDateTime);
            variables.insert(VariablesMapPair("[%current_time%]", szDateTime));
            if (szMonitorTitle.size())
                variables.insert(VariablesMapPair("[%monitor_title%]", szMonitorTitle));
            else
                variables.insert(VariablesMapPair("[%monitor_title%]", szUrl));
            variables.insert(VariablesMapPair("[%monitor_url%]", szUrl));
            variable.str("");
            variable << uiQtyTriggers;
            variables.insert(VariablesMapPair("[%changes_count%]", variable.str()));            
            variable.str("");
            variable << uiAccountID;
            variables.insert(VariablesMapPair("[%account_id%]", variable.str()));
            variable.str("");
            variable << uiMonitorID;
            variables.insert(VariablesMapPair("[%monitor_id%]", variable.str()));
            variable.str("");
            variable << uiResourceID;
            variables.insert(VariablesMapPair("[%resource_id%]", variable.str()));
            variables.insert(VariablesMapPair("[%changes_summary%]", szChangesSummary.c_str()));
            ReplaceTemplates(szTemplateText);
            ReplaceVariables(szTemplateText, variables);
            ReplaceTemplates(szSubject);
            ReplaceVariables(szSubject, variables);
            if (ucEmailContentType == CONTENT_TYPE_TEXT_PLAIN)
                ConvertTemplateToText(szTemplateText);
            if (szEmailBcc.size())
            {
                if (szDefaultEmailBcc.size())
                {
                    szDefaultEmailBcc += ";";
                    szDefaultEmailBcc += szEmailBcc;
                }
                else
                {
                    szDefaultEmailBcc = szEmailBcc;
                }
            }
            CreateEmail(szDefaultEmailFrom, szEmailTo, szDefaultEmailCc, szDefaultEmailBcc, szAttachmentFileName, szSubject, ucEmailContentType, szTemplateText, szEmailBody, szEmailSender, recipients);
            szEmailSender = szDefaultEmailFrom;
            bResult = true;
        }
    }
    catch (vmime::exception& e)
    {
        LOGT(("EmailManager::CreateEmailWithChangesSummary. VMime exception occurred. Message: %s\n", e.what()));
    }
    catch (std::exception& e)
    {
        LOGT(("EmailManager::CreateEmailWithChangesSummary. Std exception occurred. Message: %s\n", e.what()));
    }
    return bResult;
}

bool EmailManager::CreateEmailWithMonitorError(     const unsigned int& uiMonitorID,
                                                    const unsigned int& uiAccountID,
                                                    const unsigned int& uiResourceID,
                                                    const unsigned char& ucEmailContentType,
                                                    const string& szEmailTo,
                                                    const string& szEmailBcc,
                                                    const string& szMonitorTitle,
                                                    const string& szUrl,
                                                    const string& szErrorMessage,
                                                    string& szEmailBody,
                                                    string& szEmailSender,
                                                    vector<string>& recipients)
{
    bool bResult = false;
    try
    {
        string szSubject;
        string szTemplateText;
        string szDefaultEmailFrom;
        string szDefaultEmailTo;
        string szDefaultEmailCc;
        string szDefaultEmailBcc;
        if (dbLayer->GetEmailTemplate("monitor_error",  szSubject, szTemplateText, szDefaultEmailFrom, szDefaultEmailTo, szDefaultEmailCc, szDefaultEmailBcc))
        {
            VariablesMap variables;
            stringstream variable;            
            string szDateTime;

            GetGMTDateTime(szDateTime);
            variables.insert(VariablesMapPair("[%current_time%]", szDateTime));
            if (szMonitorTitle.size())
                variables.insert(VariablesMapPair("[%monitor_title%]", szMonitorTitle));
            else
                variables.insert(VariablesMapPair("[%monitor_title%]", szUrl));
            variables.insert(VariablesMapPair("[%monitor_url%]", szUrl));
            variables.insert(VariablesMapPair("[%error_message%]", szErrorMessage));
            variable.str("");
            variable << uiAccountID;
            variables.insert(VariablesMapPair("[%account_id%]", variable.str()));
            variable.str("");
            variable << uiMonitorID;
            variables.insert(VariablesMapPair("[%monitor_id%]", variable.str()));
            variable.str("");
            variable << uiResourceID;
            variables.insert(VariablesMapPair("[%resource_id%]", variable.str()));
            ReplaceTemplates(szTemplateText);
            ReplaceVariables(szTemplateText, variables);
            ReplaceTemplates(szSubject);
            ReplaceVariables(szSubject, variables);
            if (ucEmailContentType == CONTENT_TYPE_TEXT_PLAIN)
                ConvertTemplateToText(szTemplateText);
            if (szEmailBcc.size())
            {
                if (szDefaultEmailBcc.size())
                {
                    szDefaultEmailBcc += ";";
                    szDefaultEmailBcc += szEmailBcc;
                }
                else
                {
                    szDefaultEmailBcc = szEmailBcc;
                }
            }
            CreateEmail(szDefaultEmailFrom, szEmailTo, szDefaultEmailCc, szDefaultEmailBcc, "", szSubject, ucEmailContentType, szTemplateText, szEmailBody, szEmailSender, recipients);
            szEmailSender = szDefaultEmailFrom;
            bResult = true;
        }
    }
    catch (vmime::exception& e)
    {
        LOGT(("EmailManager::CreateEmailWithMonitorError. VMime exception occurred. Message: %s\n", e.what()));
    }
    catch (std::exception& e)
    {
        LOGT(("EmailManager::CreateEmailWithMonitorError. Std exception occurred. Message: %s\n", e.what()));
    }
    return bResult;
}

bool EmailManager::CreateEmailWithDHLError( const unsigned int& uiMonitorID,
                                            const unsigned int& uiAccountID, 
                                            const unsigned int& uiResourceID,
                                            const string& szMonitorTitle,
                                            const string& szUrl,
                                            const string& szErrorMessage,
                                            const unsigned char& ucEmailContentType,
                                            string& szEmailBody,
                                            string& szEmailSender,
                                            vector<string>& recipients)
{
    bool bResult = false;
    try
    {
        string szSubject;
        string szTemplateText;
        string szDefaultEmailFrom;
        string szDefaultEmailTo;
        string szDefaultEmailCc;
        string szDefaultEmailBcc;
        if (dbLayer->GetEmailTemplate("dhl_error",  szSubject, szTemplateText, szDefaultEmailFrom, szDefaultEmailTo, szDefaultEmailCc, szDefaultEmailBcc))
        {
            VariablesMap variables;
            stringstream variable;            
            string szDateTime;

            GetGMTDateTime(szDateTime);
            variables.insert(VariablesMapPair("[%current_time%]", szDateTime));
            if (szMonitorTitle.size())
                variables.insert(VariablesMapPair("[%monitor_title%]", szMonitorTitle));
            else
                variables.insert(VariablesMapPair("[%monitor_title%]", szUrl));
            variables.insert(VariablesMapPair("[%monitor_url%]", szUrl));
            variables.insert(VariablesMapPair("[%error_message%]", szErrorMessage));
            variable << uiAccountID;
            variables.insert(VariablesMapPair("[%account_id%]", variable.str()));
            variable.str("");
            variable << uiMonitorID;
            variables.insert(VariablesMapPair("[%monitor_id%]", variable.str()));
            variable.str("");
            variable << uiResourceID;
            variables.insert(VariablesMapPair("[%resource_id%]", variable.str()));
            ReplaceTemplates(szTemplateText);
            ReplaceVariables(szTemplateText, variables);
            ReplaceTemplates(szSubject);
            ReplaceVariables(szSubject, variables);
            if (ucEmailContentType == CONTENT_TYPE_TEXT_PLAIN)
                ConvertTemplateToText(szTemplateText);
            CreateEmail(szDefaultEmailFrom, szDefaultEmailTo, szDefaultEmailCc, szDefaultEmailBcc, "", szSubject, ucEmailContentType, szTemplateText, szEmailBody, szEmailSender, recipients);
            szEmailSender = szDefaultEmailFrom;
            bResult = true;
        }
    }
    catch (vmime::exception& e)
    {
        LOGT(("EmailManager::CreateEmailWithDHLError. VMime exception occurred. Message: %s\n", e.what()));
    }
    catch (std::exception& e)
    {
        LOGT(("EmailManager::CreateEmailWithDHLError. Std exception occurred. Message: %s\n", e.what()));
    }
    return bResult;
}